open Common
open Dispose
open Printf

class movie ?(title = "") ?(year = 0) (id : Int64.t) = object(self)
	val mutable _title = title
	val mutable _year = year
	val mutable _description = ""
		
	method id = id

	method title = _title
	method set_title t =
		_title <- t
			
	method year = _year
	method set_year y =
		_year <- y

	method desc = _description
	method set_desc d =
		_description <- d
end

class movies_dal dbName = object(self)
	method private use_store : 'a. (Sqlite3.db -> 'a) -> 'a =
		function f -> do_finally_p2 f Sqlite3.db_close (Sqlite3.db_open dbName)
				
	method private prepare () =
		let sql = Resources.read_file "init.sql"	in
		let exec h = 
			using
				(Store.create_multiple_stmt h sql)
				(fun sList -> List.iter Store.execute_non_query sList#value)
		in
			self#use_store exec

	initializer
		self#prepare()
				
	method load_movies () =
		let load h =
			let qStr = Resources.read_file "load_all.sql" in
				using
					(new Store.squery (Store.create_single_stmt h qStr))
					(fun q ->
						 let convert [|Sqlite3.Data.INT(id); Sqlite3.Data.TEXT(title); Sqlite3.Data.INT(year); desc|] =
							 let res = new movie ~title:title ~year:(Int64.to_int year) id in
								 (match desc with
										| Sqlite3.Data.TEXT(s) -> res#set_desc s
										| _ -> ()
								 );
								 res
						 in
							 List.map convert (q#execute_query_dataset()))
		in
			self#use_store load

	method delete_movie (m : movie) =
		let id = m#id in
		let delete h =
			let qStr = (sprintf "delete from films where rowid = %Ld; delete from descs where film_id = %Ld;" id id) in
				using
					(Store.create_multiple_stmt h qStr)
					(fun sList -> List.iter Store.execute_non_query sList#value)
		in
			self#use_store delete

	method add_movie title year desc =
		let add h =
			let sql = "insert into films (title,year) values (:001, :002); select last_insert_rowid(); insert into descs (film_id, desc, desc_lang) values (:001, :002, \"eng\");"
			in
				using
					(Store.create_multiple_stmt h sql)
					(fun sList ->
						 match sList#value with
							 | ins1 :: rowIdQuery :: ins2 :: [] -> (
									 [|Sqlite3.Data.TEXT(title); Sqlite3.Data.INT(Int64.of_int year)|] |>
											 Store.set_parameters ins1 |>
													 Store.execute_non_query;
									 
									 let Sqlite3.Data.INT(id) as sqlId = Option.get (Store.execute_scalar rowIdQuery) in
										 [| Sqlite3.Data.TEXT(desc); sqlId |] |> Store.set_parameters ins2 |> Store.execute_non_query;
										 let res = new movie ~title:title ~year:year id in
											 res#set_desc desc;
											 res
								 )
							 | _ -> failwith "Error adding new movie!")
		in
			self#use_store add
				
	(* method load_desc (movie:movie) = *)
	(* 	let id = movie#id in *)
	(* 	let load h = *)
	(* 		let sql = sprintf "select desc from descs where descs.film_id = %Ld" id in *)
	(* 			using *)
	(* 				(Store.create_single_stmt h sql) *)
	(* 				(fun q -> *)
	(* 					 match Store.execute_scalar q with *)
	(* 						 | Some( Sqlite3.Data.TEXT(s) ) -> s *)
	(* 						 | None -> "" *)
	(* 						 | _ -> failwith "Wrong type for movie description!") *)
	(* 		in *)
	(* 			self#use_store load *)
end
